﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace NeuralNetworks
{
    public delegate void SetTrainingResultsLabelTextDelegate(string text);
    public delegate void UpdateTrainingControlsDelegate(bool trainingStarted);
    public delegate void SetTrainingProgressBarValueDelegate(int value);

    public partial class ORUserControl : UserControl
    {
        #region Constructors

        public ORUserControl()
        {
            InitializeComponent();
        }

        #endregion

        #region Private Members

        Thread _trainingThread;

        #endregion

        #region Attributes and Properties

        private NeuralNetwork _network;
        public NeuralNetwork Network
        {
            get { return _network; }
            set { _network = value; }
        }

        #endregion

        #region Private Methods

        private void TrainNeuralNetwork()
        {
            this.SetTrainingProgressBarValue(0);
            this.SetTrainingResultsLabelText(string.Empty);
            this.UpdateTrainingControls(true);

            short[] result;
            int i = 0;
            do
            {
                int c = 0;
                _network.ResetHigherErrorFactor();

                result = _network.Train(new short[] { 0, 0 }, new short[] { 0 });
                if (_network.LastHigherError <= 0.1f)
                    c++;
                result = _network.Train(new short[] { 0, 1 }, new short[] { 1 });
                if (_network.LastHigherError <= 0.1f)
                    c++;
                result = _network.Train(new short[] { 1, 0 }, new short[] { 1 });
                if (_network.LastHigherError <= 0.1f)
                    c++;
                result = _network.Train(new short[] { 1, 1 }, new short[] { 1 });
                if (_network.LastHigherError <= 0.1f)
                    c++;

                this.SetTrainingProgressBarValue(c);

                i++;
            }
            while (_network.HigherErrorFactor > 0.1f);

            this.SetTrainingResultsLabelText(string.Format("Treinado em {0} iterações.", i));
            this.UpdateTrainingControls(false);
        }

        private void SetTrainingResultsLabelText(string text)
        {
            if (_trainingResultsLabel.InvokeRequired)
                _trainingResultsLabel.Invoke(new SetTrainingResultsLabelTextDelegate(SetTrainingResultsLabelText), text);
            else
                _trainingResultsLabel.Text = text;
        }

        private void UpdateTrainingControls(bool trainingStarted)
        {
            if (_trainingProgressBar.InvokeRequired)
                _trainingProgressBar.Invoke(new UpdateTrainingControlsDelegate(UpdateTrainingControls), trainingStarted);
            else
            {
                _trainingProgressBar.Visible = trainingStarted;
                _trainButton.Enabled = !trainingStarted;
                _stopButton.Visible = trainingStarted;
            }
        }

        private void SetTrainingProgressBarValue(int value)
        {
            if (_trainingProgressBar.InvokeRequired)
                _trainingProgressBar.Invoke(new SetTrainingProgressBarValueDelegate(SetTrainingProgressBarValue), value);
            else
                _trainingProgressBar.Value = value;
        }

        #endregion

        #region Signed Events Methods

        private void CalculateButton_Click(object sender, EventArgs e)
        {
            var values = new short[]
            {
                (short)_firstOperandNumericUpDown.Value,
                (short)_secondOperandNumericUpDown.Value
            };

            short[] result = _network.Calculate(values);

            _resultTextBox.Text = result[0].ToString();
        }

        private void TrainButton_Click(object sender, EventArgs e)
        {
            _trainingThread = new Thread(TrainNeuralNetwork);
            _trainingThread.Start();
        }

        private void _stopButton_Click(object sender, EventArgs e)
        {
            if (_trainingThread == null)
                return;

            _trainingThread.Abort();
            _trainingThread = null;
            this.UpdateTrainingControls(false);
        }

        #endregion
    }
}
